﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BneyBaruch.Ingest.MorningLesson.Contracts.Interfaces;
using System.ServiceModel;
using BneyBaruch.Ingest.MorningLesson.Contracts.Messages;
using BneyBaruch.Ingest.Core.WorkflowCommunication.Extensions;
using System.Workflow.Activities;
using System.Workflow.Runtime;
using BneyBaruch.Ingest.MorningLesson.WorkflowServices;
using BneyBaruch.Ingest.MorningLesson.Workflow;
using BneyBaruch.Ingest.Core.ServiceModel;
using System.Threading;

namespace BneyBaruch.Ingest.MorningLesson.WorkflowProcessorServices
{
    [ServiceBehavior
        (
            InstanceContextMode = InstanceContextMode.Single,
            ConcurrencyMode=ConcurrencyMode.Reentrant
        )
    ]
    public class MorningLessonWorkflowProcessor : IMorningLessonWorkflowProcessor
    {
        #region Constants

        private const string MorningLessonWorkflowManagerServerEndpointConfigurationName = "MorningLessonWorkflowManagerServerEndpoint";

        #endregion

        #region Fields

        private WorkflowRuntime workflowRuntime;
        private Dictionary<Guid, IMorningLessonWorkflowProcessorCallback> clients;
        private MorningLessonInjestWorkflowLocalService morningLessonInjestWorkflowLocalService;
        private MorningLessonWorkflowManagerCallback morningLessonWorkflowManagerCallback;

        #endregion

        #region Constructors

        public MorningLessonWorkflowProcessor()
        {
            clients = new Dictionary<Guid, IMorningLessonWorkflowProcessorCallback>();
        }

        #endregion

        #region IMorningLessonWorkflowProcessor Members

        public StartWorkflowResponse StartWorkflow(StartWorkflowRequest request)
        {
            SetUpWorkflowEnvironment();

            // Create a new instance of the SequentialWorkflow and submit it to the WorkflowRuntime

            Guid workflowInstanceId = request.WorkflowId;

            WorkflowInstance workflowInstance =
                workflowRuntime.CreateWorkflow(typeof(MorningLessonInjestWorkflow), null, workflowInstanceId);
            workflowInstance.Start();

            IMorningLessonWorkflowProcessorCallback caller =
                OperationContext.Current.GetCallbackChannel<IMorningLessonWorkflowProcessorCallback>();

            if (caller != null)
            {
                if (!clients.ContainsKey(workflowInstanceId))
                    clients.Add(workflowInstanceId, caller);
            }

            ThreadPool.QueueUserWorkItem( InteractManagerForMatrixAdjustment , workflowInstanceId );

            return new StartWorkflowResponse(workflowInstanceId);
        }

        private void InteractManagerForMatrixAdjustment(object state)
        {
            Guid workflowId = (Guid)state;
            DuplexServiceProxy<IMorningLessonWorkflowManager>.Call(
                proxy =>
                {
                    proxy.RequestManagerForMatrixAdjustment(new RequestManagerForMatrixAdjustmentRequest(workflowId,"Please,approve matrix adjustment"));
                } // Service proxy delegate call.
                ,
                new InstanceContext(morningLessonWorkflowManagerCallback)
                ,
                MorningLessonWorkflowManagerServerEndpointConfigurationName // Endpoint configuration name
            );
        }

        #endregion

        #region Private Workflow Methods

        /// <summary>
        /// Ensures that the instance of MorningLessonInjestWorkflowLocalService has been initialized
        /// and added to the workflow's data exchange
        /// </summary>
        /// <remarks>
        /// There will only be a single instance of this object in activation
        /// at any point in time.
        /// </remarks>
        private void SetUpWorkflowEnvironment()
        {
            if (morningLessonInjestWorkflowLocalService == null)
            {
                WorkflowRuntimePerServiceContainer extension =
                    OperationContext.Current.Host.Extensions.Find<WorkflowRuntimePerServiceContainer>();

                workflowRuntime = extension.WorkflowRuntime;

                // We will try and fetch the instance from the active WorkflowRuntime's
                // ExtenalDataExchangeService and if it currently does not have an
                // activated instance, we will create a new instance and add it.
                ExternalDataExchangeService dataExchangeService =
                    workflowRuntime.GetService<ExternalDataExchangeService>();

                morningLessonInjestWorkflowLocalService =
                    (MorningLessonInjestWorkflowLocalService)dataExchangeService.GetService(typeof(MorningLessonInjestWorkflowLocalService));

                if (morningLessonInjestWorkflowLocalService == null)
                {
                    morningLessonInjestWorkflowLocalService =
                        new MorningLessonInjestWorkflowLocalService(workflowRuntime);
                    dataExchangeService.AddService(morningLessonInjestWorkflowLocalService);
                }

                morningLessonWorkflowManagerCallback = new MorningLessonWorkflowManagerCallback(morningLessonInjestWorkflowLocalService);

                // Events are then wired up to our local event handlers
                morningLessonInjestWorkflowLocalService.MatrixAdjustmentApproved +=
                    new EventHandler<MatrixAdjustmentApprovedEventArgs>(morningLessonInjestWorkflowLocalService_MatrixAdjustmentApproved);
            }
        }

        #endregion

        #region MorningLessonInjestWorkflowLocalService Events Handlers

        void morningLessonInjestWorkflowLocalService_MatrixAdjustmentApproved(object sender, MatrixAdjustmentApprovedEventArgs e)
        {
        }

        #endregion
    }
}
